#include "video/video.h"
#include "sys.h"

struct video_driver* video_vgagraphics_driver;
unsigned int video_vgagraphics_framebuffersegment;



static void vpokeb(unsigned off, unsigned val)
{
	pokeb(vga_getframebuffersegment(), off, val);
}

static unsigned vpeekb(unsigned off)
{
	return peekb(vga_getframebuffersegment(), off);
}
static unsigned g_vgabase_wd;

void vga_write_pixel1(unsigned x, unsigned y, unsigned c)
{
	unsigned wd_in_bytes;
	unsigned off, mask;

	c = (c & 1) * 0xFF;
	wd_in_bytes = g_vgabase_wd / 8;
	off = wd_in_bytes * y + x / 8;
	x = (x & 7) * 1;
	mask = 0x80 >> x;
	vpokeb(off, (vpeekb(off) & ~mask) | (c & mask));
}

void vga_write_pixel2(unsigned x, unsigned y, unsigned c)
{
	unsigned wd_in_bytes, off, mask;

	c = (c & 3) * 0x55;
	wd_in_bytes = g_vgabase_wd / 4;
	off = wd_in_bytes * y + x / 4;
	x = (x & 3) * 2;
	mask = 0xC0 >> x;
	vpokeb(off, (vpeekb(off) & ~mask) | (c & mask));
}

void vga_write_pixel4p(unsigned x, unsigned y, unsigned c)
{
	unsigned wd_in_bytes, off, mask, p, pmask;

	wd_in_bytes = g_vgabase_wd / 8;
	off = wd_in_bytes * y + x / 8;
	x = (x & 7) * 1;
	mask = 0x80 >> x;
	pmask = 1;
	for(p = 0; p < 4; p++)
	{
		vga_setplane(p);
		if(pmask & c)
			vpokeb(off, vpeekb(off) | mask);
		else
			vpokeb(off, vpeekb(off) & ~mask);
		pmask <<= 1;
	}
}

void vga_write_pixel8(unsigned x, unsigned y, unsigned c)
{
	unsigned wd_in_bytes;
	unsigned off;

	wd_in_bytes = g_vgabase_wd;
	off = wd_in_bytes * y + x;
	vpokeb(off, c);
}

void vga_write_pixel8x(unsigned x, unsigned y, unsigned c)
{
	unsigned wd_in_bytes;
	unsigned off;

	wd_in_bytes = g_vgabase_wd / 4;
	off = wd_in_bytes * y + x / 4;
	vga_setplane(x & 3);
	vpokeb(off, c);
}

unsigned char g_vgagraphics_640x480x1[] =
{
/* MISC */
	0xE3,
/* SEQ */
	0x03, 0x01, 0x0F, 0x00, 0x06,
/* CRTC */
	0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E,
	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xEA, 0x0C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3,
	0xFF,
/* GC */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0F,
	0xFF,
/* AC */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
	0x01, 0x00, 0x0F, 0x00, 0x00
};

unsigned char g_vgagraphics_320x200x2[] =
{
/* MISC */
	0x63,
/* SEQ */
	0x03, 0x09, 0x03, 0x00, 0x02,
/* CRTC */
	0x2D, 0x27, 0x28, 0x90, 0x2B, 0x80, 0xBF, 0x1F,
	0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x9C, 0x0E, 0x8F, 0x14, 0x00, 0x96, 0xB9, 0xA3,
	0xFF,
/* GC */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x02, 0x00,
	0xFF,
/* AC */
	0x00, 0x13, 0x15, 0x17, 0x02, 0x04, 0x06, 0x07,
	0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
	0x01, 0x00, 0x03, 0x00, 0x00
};

unsigned char g_vgagraphics_640x480x4[] =
{
/* MISC */
	0xE3,
/* SEQ */
	0x03, 0x01, 0x08, 0x00, 0x06,
/* CRTC */
	0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0x0B, 0x3E,
	0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xEA, 0x0C, 0xDF, 0x28, 0x00, 0xE7, 0x04, 0xE3,
	0xFF,
/* GC */
	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F,
	0xFF,
/* AC */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x14, 0x07,
	0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
	0x01, 0x00, 0x0F, 0x00, 0x00
};

unsigned char g_vgagraphics_720x480x4[] =
{
/* MISC */
	0xE7,
/* SEQ */
	0x03, 0x01, 0x08, 0x00, 0x06,
/* CRTC */
	0x6B, 0x59, 0x5A, 0x82, 0x60, 0x8D, 0x0B, 0x3E,
	0x00, 0x40, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00,
	0xEA, 0x0C, 0xDF, 0x2D, 0x08, 0xE8, 0x05, 0xE3,
	0xFF,
/* GC */
	0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x05, 0x0F,
	0xFF,
/* AC */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	0x01, 0x00, 0x0F, 0x00, 0x00,
};

unsigned char g_vgagraphics_320x200x8[] =
{
/* MISC */
	0x63,
/* SEQ */
	0x03, 0x01, 0x0F, 0x00, 0x0E,
/* CRTC */
	0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
	0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x9C, 0x0E, 0x8F, 0x28,	0x40, 0x96, 0xB9, 0xA3,
	0xFF,
/* GC */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
	0xFF,
/* AC */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	0x41, 0x00, 0x0F, 0x00,	0x00
};

unsigned char g_vgagraphics_320x200x8_modex[] =
{
/* MISC */
	0x63,
/* SEQ */
	0x03, 0x01, 0x0F, 0x00, 0x06,
/* CRTC */
	0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
	0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x9C, 0x0E, 0x8F, 0x28, 0x00, 0x96, 0xB9, 0xE3,
	0xFF,
/* GC */
	0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
	0xFF,
/* AC */
	0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
	0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
	0x41, 0x00, 0x0F, 0x00, 0x00
};

struct video_driver* video_vgagraphics_getdriver()
{
    return video_vgagraphics_driver;
}

void video_vgagraphics_start(unsigned int mode)
{
    vga_writeregs(g_vgagraphics_320x200x8);
    video_vgagraphics_framebuffersegment=vga_getframebuffersegment();
    g_vgabase_wd=320;
}

void video_vgagraphics_end()
{

}

void video_vgagraphics_putpixel(unsigned int x,unsigned int y,unsigned int colour)
{
*(unsigned char*)(video_vgagraphics_framebuffersegment+320*y+x)=colour&0xFF;
}

unsigned int video_vgagraphics_getpixel(unsigned int x,unsigned int y)
{
    return 0;
}

void video_vgagraphics_cls()
{
    unsigned int i;
    for(i=0;i<4000;i++)
    {
        *(unsigned int*)(video_vgagraphics_framebuffersegment+(i<<4))=0;
        *(unsigned int*)(video_vgagraphics_framebuffersegment+(i<<4)+4)=0;
        *(unsigned int*)(video_vgagraphics_framebuffersegment+(i<<4)+8)=0;
        *(unsigned int*)(video_vgagraphics_framebuffersegment+(i<<4)+12)=0;
    }
}


struct video_displaymode video_vgagraphics_displaymodes[1] =
{
    {3,320,200,8}
};

void video_vgagraphics_init(struct video_driver* Driver)
{
//Set variables
    Driver->displaymode=video_vgagraphics_displaymodes;
    Driver->displaymodecount=1;
    Driver->start=video_vgagraphics_start;
    Driver->end=video_vgagraphics_end;
    Driver->putchar=0;
    Driver->getchar=0;
    Driver->positioncursor=0;
    Driver->putpixel=video_vgagraphics_putpixel;
    Driver->getpixel=video_vgagraphics_getpixel;
    Driver->cls=video_vgagraphics_cls;

//Set driver
    video_vgagraphics_driver=Driver;
}
